---
title: ビュートランジション
description: >-
  ビュートランジションを使用して、Astroでページ間のシームレスなナビゲーションを実現する。
i18nReady: true
---

import Since from '~/components/Since.astro'

Astroでは、**オプトイン式ページ単位のビュートランジション**を数行のコードで実現できます。ビュートランジションは、ブラウザがナビゲーション時に通常おこなうページ全体の更新なしでページコンテンツを更新し、ページ間のシームレスなアニメーションを提供します。

Astroは、単一のページの`<head>`に追加可能な`<ViewTransitions />`ルーティングコンポーネントを提供しており、これにより別のページに移動する際のページ遷移を制御できます。このコンポーネントは軽量なクライアントサイドルーターを提供し、[ナビゲーションをインターセプト](#クライアントサイドナビゲーションの流れ)してページ間の遷移をカスタマイズできるようにします。

このコンポーネントを共通のヘッドやレイアウトなど再利用可能な`.astro`コンポーネントに追加すると、サイト全体でのアニメーション付きのページ遷移（SPAモード）が可能になります。

Astroのビュートランジションは新しい[View Transitions](https://developer.chrome.com/docs/web-platform/view-transitions/)ブラウザAPIによって提供されており、また以下の機能も含みます。

- `fade`や`slide`、`none`など、いくつかの[組み込みのアニメーションオプション](#組み込みのアニメーションディレクティブ)。
- 戻る・進むの両ナビゲーションでのアニメーションのサポート。
- [トランジションアニメーションのすべての要素を完全にカスタマイズ](#アニメーションをカスタマイズする)し、さらに独自のアニメーションを作成する機能。
- [非ページへのリンクに対しクライアントサイドナビゲーションを防止する](#クライアントサイドナビゲーションの防止)オプション。
- まだView Transition APIをサポートしていないブラウザのための[フォールバック用動作の制御](#フォールバックの制御)。
- [`prefers-reduced-motion`](#prefers-reduced-motion)の自動サポート。

:::note
デフォルトでは、すべてのページは通常のフルページのブラウザナビゲーションを使用します。ビュートランジションを有効化すると、ページ単位またはサイト全体で使用できます。
:::

## ページにビュートランジションを追加する

`ViewTransitions />`ルーティングコンポーネントをインポートし、`<head>`内に追加することで、ビュートランジションを個別のページで有効化できます。

```astro title="src/pages/index.astro" ins={2,7}
---
import { ViewTransitions } from 'astro:transitions';
---
<html lang="ja">
  <head>
    <title>私のホームページ</title>
    <ViewTransitions />
  </head>
  <body>
    <h1>私のウェブサイトへようこそ！</h1>
  </body>
</html>
```

## サイト全体でのビュートランジション（SPAモード）

`<ViewTransitions />`をインポートし、共通の`<head>`または共有のレイアウトコンポーネントに追加します。Astroは、旧ページと新ページの類似点に基づいてデフォルトのページアニメーションを作成し、サポートされていないブラウザに対するフォールバック動作も提供します。

以下の例では、このコンポーネントをインポートし`<CommonHead />` Astroコンポーネントに追加することで、Astroのデフォルトのページナビゲーションアニメーションをサイト全体に追加しています。これにより、サポートされていないブラウザに対するフォールバック動作も追加されます。

```astro title="components/CommonHead.astro" ins={2,12}
---
import { ViewTransitions } from 'astro:transitions';
---
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />

<!-- 主要メタタグ -->
<title>{title}</title>
<meta name="title" content={title} />
<meta name="description" content={description} />

<ViewTransitions />
```

Astroのデフォルトのクライアントサイドナビゲーションを有効にするために、他に必要な設定はありません！

より細かな制御のためには、[トランジションディレクティブ](#トランジションディレクティブ)を使用するか、個々の要素で[デフォルトのクライアントサイドナビゲーションをオーバーライド](#クライアントサイドナビゲーションの防止)します。

## トランジションディレクティブ

Astroは、旧ページと新ページの両方に存在する対応する要素に、共通かつ一意の`view-transition-name`を自動的に割り当てます。マッチする要素のペアは、要素の種類とDOM内の位置の両方によって推測されます。

`.astro`コンポーネント内のページ要素にオプションの`transition:*`ディレクティブを使用すると、ナビゲーション中のページ遷移の動作をより細かく制御できます。

- `transition:name`: 新旧コンテンツのアニメーションに関するAstroデフォルトの要素のマッチング方式をオーバーライドし、DOM要素のペアを関連付ける[トランジション名を指定](#トランジションに名前を付ける)できます。
- `transition:animate`: アニメーションの種類を指定することで、旧要素を新要素で置き換える際のAstroのデフォルトのアニメーションをオーバーライドできます。Astroの[組み込みのアニメーションディレクティブ](#組み込みのアニメーションディレクティブ)を使用するか、[独自のトランジションアニメーションを作成](#アニメーションをカスタマイズする)します。
- `transition:persist`: 旧要素を新要素で置き換えるAstroのデフォルトの挙動をオーバーライドし、[別のページに移動した際にコンポーネントとHTML要素を保持](#状態を保持する)します。


### トランジションに名前を付ける

場合によっては、対応するビュートランジション要素を自分で特定したい、または特定する必要があるかもしれません。`transition:name`ディレクティブを使用して、要素のペアに名前を付けることができます。

```astro title="old-page.astro"
<aside transition:name="hero">
```

```astro title="new-page.astro"
<aside transition:name="hero">
```

`transition:name`に使った値は、各ページにつき1回しか使用できないことに注意してください。Astroが適切な名前を自動的に推測できない場合や、要素のマッチングをより細かく制御したい場合に、手動で設定してください。

### 状態を保持する

<Since v="2.10.0" />

`transition:persist`ディレクティブを使用すると、ページ間のナビゲーションでコンポーネントとHTML要素を（置き換えるのではなく）保持できます。

たとえば以下の`<video>`は、同じvideo要素を含む別のページに移動しても再生され続けます。これは、進む・戻るの両方のナビゲーションで機能します。

```astro title="components/Video.astro" "transition:persist"
<video controls="" autoplay="" transition:persist>
	<source src="https://ia804502.us.archive.org/33/items/GoldenGa1939_3/GoldenGa1939_3_512kb.mp4" type="video/mp4">
</video>
```

[Astroアイランド](/ja/concepts/islands/)（[`client:`ディレクティブ](/ja/reference/directives-reference/#client-directives)をもつUIフレームワークコンポーネント）にもディレクティブを配置できます。そのコンポーネントが次のページに存在する場合、旧ページのアイランドは**現在の状態のまま**表示され、新しいページのアイランドに置き換えられることはありません。

以下の例では、`transition:persist`属性をもつ`<Counter />`コンポーネントを含むページ間を行き来しても、`count`はリセットされません。

```astro title="components/Header.astro" "transition:persist"
<Counter client:load transition:persist count={5} />
```

また、アイランドあるいは要素が2つのページ間で異なるコンポーネントの中にある場合は、[対応する要素を手動で特定](#トランジションに名前を付ける)できます。

```astro title="pages/old-page.astro" "Video" 'transition:name="media-player"'
<Video controls="" autoplay="" transition:name="media-player" transition:persist />
```

```astro title="pages/new-page.astro" "MyVideo" 'transition:name="media-player"'
<MyVideo controls="" autoplay="" transition:name="media-player" transition:persist />
```

便利な短縮記法として、`transition:persist`の値にトランジション名を指定できます。

```astro title="pages/index.astro" '="media-player"'
<video controls="" autoplay="" transition:persist="media-player">
```

### 組み込みのアニメーションディレクティブ

Astroには、デフォルトの`fade`トランジションをオーバーライドするための組み込みのアニメーションがいくつか用意されています。`transition:animate`ディレクティブを各要素に追加して、特定のトランジションの動作をカスタマイズできます。

- `fade`（デフォルト）: 独自のクロスフェードアニメーションです。旧コンテンツがフェードアウトし、新コンテンツがフェードインします。
- `initial`: Astroの独自のクロスフェードアニメーションを無効にし、ブラウザのデフォルトのスタイルを使用します。
- `slide`: 旧コンテンツが左にスライドアウトし、新コンテンツが右からスライドインするアニメーションです。戻る場合のナビゲーションでは、アニメーションは逆になります。
- `fade`: 旧コンテンツがフェードアウトし、新コンテンツがフェードインするクロスフェードです。
- `none`: ブラウザのデフォルトのアニメーションを無効にします。ページの`<html>`要素で使用すると、ページ内のすべての要素のデフォルトのフェードを無効にします。

ページのアニメーションを完全に制御するには、ディレクティブを組み合わせます。`<html>`要素でページのデフォルト値を設定し、必要に応じて個々の要素でオーバーライドしてください。

以下の例では、ボディコンテンツにスライドアニメーションを設定し、ページの残りの部分に対してはブラウザのデフォルトのフェードアニメーションを無効にしています。

```astro
---
import { CommonHead } from '../components/CommonHead.astro';
---
<html transition:animate="none">
  <head>
    <CommonHead />
  </head>
  <body>
    <header>
      ...
    </header>
    <!-- 個別の要素でページデフォルトをオーバーライドします -->
    <main transition:animate="slide">
      ...
    </main>
  </body>
</html>
```

### アニメーションをカスタマイズする

任意のCSSアニメーションプロパティを使用して、トランジションのすべての要素をカスタマイズできます。

組み込みのアニメーションをカスタマイズするには、まず`astro:transitions`からアニメーションをインポートし、続いてカスタマイズ用オプションを渡します。

以下の例では、組み込みの`fade`アニメーションの継続時間（duration）をカスタマイズしています。

```astro
---
import { fade } from 'astro:transitions';
---

<header transition:animate={fade({ duration: '0.4s' })}>
```

また、`transition:animate`で独自のアニメーションも定義できます。進む・戻るの挙動と新旧のページについて、以下の型に従って定義します。

```ts
export interface TransitionAnimation {
  name: string; // キーフレームの名前
  delay?: number | string;
  duration?: number | string;
  easing?: string;
	fillMode?: string;
	direction?: string;
}

export interface TransitionAnimationPair {
	old: TransitionAnimation | TransitionAnimation[];
	new: TransitionAnimation | TransitionAnimation[];
}

export interface TransitionDirectionalAnimations {
	forwards: TransitionAnimationPair;
	backwards: TransitionAnimationPair;
}
```

以下の例は、独自の`fade`アニメーションを定義するために必要なすべてのプロパティを示しています。

```astro
---
const anim = {
  old: {
    name: 'fadeIn',
    duration: '0.2s',
    easing: 'linear',
    fillMode: 'forwards',
  },
  new: {
    name: 'fadeOut',
    duration: '0.3s',
    easing: 'linear',
    fillMode: 'backwards',
  }
};

const myFade = {
	forwards: anim,
	backwards: anim,
};
---

<header transition:animate={myFade}> ... </header>
```

## クライアントサイドナビゲーションの防止

`<ViewTransitions />`コンポーネントを追加してページでクライアントサイドルーティングを有効にすると、サイト内の別のページにリンクするページ内のすべてのアンカーは、クライアントサイドルーティングによってナビゲートされます。ただ、クライアントサイドルーティングでナビゲートしたくないような場合もあります。たとえば、`public/`フォルダ内のPDFや、画像を生成するAPIルートなどの非ページへのリンクです。

こうした場合、`data-astro-reload`属性を使用して、リンクごとにクライアントサイドルーティングをオプトアウトできます。

```html
<a href="/quarterly-earnings.pdf" data-astro-reload>
```

これらのリンクはルーターによって無視され、フルページのナビゲーションが発生します。

## フォールバックの制御

`<ViewTransitions />`ルーターは、ビュートランジションをサポートするブラウザ（すなわちChromiumブラウザ）で最も有効に機能しますが、他のブラウザに対するデフォルトのフォールバックサポートも含んでいます。ブラウザがView Transitions APIをサポートしていなくても体験を損なわないように、Astroはフォールバックオプションのいずれかを使用してブラウザ内でのナビゲーションを提供します。

`<ViewTransitions />`コンポーネントに`fallback`プロパティを追加し、`swap`または`none`に設定することで、Astroのデフォルトのフォールバックサポートをオーバーライドできます。

- `animate` (デフォルト、推奨) - Astroは、ページコンテンツを更新する前に、カスタム属性を使用してビュートランジションをシミュレートします。
- `swap` - Astroはページのアニメーションを試みません。代わりに、旧ページはすぐに新しいページに置き換えられます。
- `none` - Astroはアニメーションによるページ遷移を一切おこないません。代わりに、サポート外のブラウザではフルページのナビゲーションがおこなわれます。

```astro
---
import { ViewTransitions } from 'astro:transitions';
---
<title>私のサイト</title>

<ViewTransitions fallback="swap">
```

:::note[既知の制限]
`initial`ブラウザアニメーションはAstroによってシミュレートされません。そのため、このアニメーションを使用する要素は現在アニメーションされません。
:::

## クライアントサイドナビゲーションの流れ

`<ViewTransitions />`ルーターを使用すると、以下の流れでAstroのクライアントサイドナビゲーションが実行されます。

1. サイト訪問者が以下のいずれかのアクションを実行し、ナビゲーションがトリガーされる。
    - サイト内の別のページへ内部リンクする`<a>`タグをクリックする。
    - 戻るボタンをクリックする。
    - 進むボタンをクリックする。
2. ルーターが次のページの取得を開始する。
3. ルーターが、`'forward'`または`'back'`の値をもつ`data-astro-transition`属性をHTML要素に追加する。
4. ルーターが`document.startViewTransition`をコールする。これにより、ブラウザの[view transition process](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API#the_view_transition_process)がトリガーされる。重要なこととして、ブラウザはページの現在の状態をスクリーンショットする。
5. `startViewTransition`コールバック内で、ルーターが**swap**を実行する。これは以下の一連のイベントから構成される。

    - `<head>`のコンテンツが、いくつかの要素を残して入れ替わる。
        - FOUCを防止するために、スタイルシートのDOMノードが新しいページに存在する場合は残される。
        - 新しいページにスクリプトが存在する場合は残される。
        - 新しいページに対応する要素がある場合、`transition:persist`をもつ他のhead要素は残される。

    - `<body>`は、新しいページのbodyに完全に置き換えられる。

    - `transition:persist`とマークされた要素が新しいページに存在する場合、新しいDOMに移動する。

    - 必要に応じてスクロール位置が復元される。

    - `astro:after-swap`イベントが`document`でトリガーされる。これが**swap**プロセスの終わりとなる。

6. ルーターが、トランジションを解決する前に新しいスタイルシートのロードを待つ。
7. ルーターが、ページに追加された新しいスクリプトを実行する。
8. `astro:page-load`イベントが発火する。これがナビゲーションプロセスの終わりとなる。

## ページナビゲーション中のスクリプトの動作

`<ViewTransitions />`コンポーネントを使用してページ間をナビゲートする際、ブラウザの動作に合わせてスクリプトが順に実行されます。

グローバルな状態を設定しているコードがある場合は、そのスクリプトが複数回実行される可能性があることを考慮する必要があります。`<script>`タグでグローバルな状態をチェックし、可能な限り条件付きでコードを実行してください。

```astro
<script is:inline>
  if(!window.SomeGlobal) {
    window.SomeGlobal = {} // ....
  }
</script>
```

モジュールスクリプトは、ブラウザがロード済みのモジュールを追跡しているため、常に1回だけ実行されます。これらのスクリプトでは再実行の心配は必要ありません。

### `astro:page-load`

新しいページがユーザーに表示され、ブロッキングスタイルとスクリプトがロードされたあとの、ページナビゲーションの最後に発生するイベントです。`document`でこのイベントをリッスンできます。

`<ViewTransitions />`コンポーネントは、初回のページナビゲーション（MPA）と、その後の進む・戻るのナビゲーションの両方でこのイベントを発生させます。

このイベントを使用すると、すべてのページナビゲーションでコードを実行したり、あるいは1度だけ実行したりできます。

```astro "{ once: true }"
<script>
  document.addEventListener('astro:page-load', () => {
    // これは1度だけ実行されます。
    setupStuff();
  }, { once: true });
</script>
```

### `astro:after-swap`

旧ページが新ページに置き換わった直後に発生するイベントです。`document`でこのイベントをリッスンできます。

このイベントは、新しいページに引き継ぐ必要があるDOM上の状態を復元するのに役立ちます。

たとえばダークモードのサポートを実装している場合、このイベントを使用してページロード間で状態を復元できます。

```astro
<script>
	const setDarkMode = () => {
		if (localStorage.darkMode) {
			document.documentElement.dataset.dark = '';
		}
	};

  // 初回のナビゲーションで実行される
	setDarkMode();
  // ビュートランジションのナビゲーションで実行される
	document.addEventListener('astro:after-swap', setDarkMode);
</script>
```

## `prefers-reduced-motion`

Astroの`<ViewTransitions />`コンポーネントにはCSSメディアクエリが含まれており、[`prefer-reduced-motion`](https://developer.mozilla.org/ja/docs/Web/CSS/@media/prefers-reduced-motion)の設定が検出された場合、フォールバックアニメーションを含む*すべての*ビュートランジションアニメーションが無効になります。代わりに、ブラウザはアニメーションなしでDOM要素を単純に入れ替えます。

## v2.xからv3.0へのアップグレード

Astro v3.0では、ビュートランジションを使うために実験的なフラグは不要となりました。

Astro 2.xでこの実験的なフラグを有効にしていなかった場合、プロジェクトへの破壊的な変更はありません。新しいビュートランジションAPIは、既存のコードに影響を与えません。

実験的なビュートランジションを使用していた場合、以前のバージョンからAstroプロジェクトをアップグレードする際に、いくつかの破壊的な変更が発生する可能性があります。

**`experimental.viewTransitions: true`が設定されたAstro v2.xプロジェクト**をv3.0にアップグレードするためには、以下の手順に従ってください。

### `experimental.viewTransitions`からのアップグレード

ビュートランジションの実験的なフラグを有効にしていた場合、Astro v3.0ではデフォルトでビュートランジションが有効になっているため、プロジェクトを更新する必要があります。

#### `experimental.viewTransitions`フラグの削除

実験的なフラグを削除します。

```js title="astro.config.mjs" del={4-6}
import { defineConfig } from 'astro/config';

export default defineConfig({
  experimental: {
    viewTransitions: true
  }
});
```

#### インポートソースの更新

`<ViewTransitions />`コンポーネントは`astro:components`から`astro:transitions`に移動しました。プロジェクト内のすべてのインポートソースを更新してください。

```astro title="src/layouts/BaseLayout.astro" del="astro:components" ins="astro:transitions"
---
import { ViewTransitions } from "astro:components astro:transitions"
---
<html lang="ja">
  <head>
    <title>私のホームページ</title>
    <ViewTransitions />
  </head>
  <body>
    <h1>私のウェブサイトへようこそ！</h1>
  </body>
</html>
```

#### `transition:animate`ディレクティブの更新

**変更:** `transition:animate`の値`morph`は`initial`へとリネームされました。また、これはデフォルトのアニメーションではなくなりました。`transition:animate`ディレクティブが指定されていない場合、アニメーションはデフォルトで`fade`になります。

1. `morph`アニメーションを`initial`にリネームします。
    ```astro title="src/components/MyComponent.astro" del="morph" ins="initial"
    <div transition:name="name" transition:animate="morph initial" />
    ```
2. デフォルトの`morph`を使っていたアニメーションを維持するには、`transition:animate="initial"`を明示的に追加します。

    ```astro title="src/components/MyComponent.astro" ins='transition:animate="initial"'
    <div transition:name="name" transition:animate="initial" />
    ```
3. 明示的に`fade`に設定されていたアニメーションは安全に削除できます。これは現在デフォルトの動作となりました。

    ```astro title="src/components/MyComponent.astro" del="transition:animate=\"fade\""
    <div transition:name="name" transition:animate="fade" />
    ```

**追加:** Astroは`transition:animate`の値として新たに`none`をサポートしました。この値をページの`<html>`要素に使用すると、ページ全体のアニメーションを無効にできます。これにより、アニメーションディレクティブをもたないページ要素のデフォルトのアニメーションがオーバーライドされます。個々の要素にアニメーションを設定することはでき、指定したアニメーションが実行されます。

4. 個々のページでデフォルトのトランジションをすべて無効にし、`transition:animate`ディレクティブを明示的に使用している要素のアニメーションだけを有効化できます。

    ```astro ins="transition:animate=\"none\""
    <html transition:animate="none">
      <head></head>
      <body>
        <h1>Hello world!</h1>
      </body>
    </html>
    ```

#### イベント名の更新

`astro:load`イベントは`astro:page-load`にリネームされました。プロジェクト内でこのイベント名を使っているすべての箇所をリネームしてください。

```astro title="src/components/MyComponent.astro" del="astro:load" ins="astro:page-load"
<script>
document.addEventListener('astro:load astro:page-load', runSetupLogic);
</script>
```

`astro:beforeload`イベントは`astro:after-swap`にリネームされました。プロジェクト内でこのイベント名を使っているすべての箇所をリネームしてください。

```astro title="src/components/MyComponent.astro" del="astro:beforeload" ins="astro:after-swap"
<script>
document.addEventListener('astro:beforeload astro:after-swap', setDarkMode);
</script>
```
